package com.greenold.task;

import com.greenold.common.utils.SecurityUtils;
import com.greenold.service.domain.CareLevel;
import com.greenold.service.domain.CarePlanItem;
import com.greenold.service.domain.CareTask;
import com.greenold.service.domain.vo.CheckInConfigVO;
import com.greenold.service.mapper.CareLevelMapper;
import com.greenold.service.mapper.CareTaskMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.temporal.ChronoUnit;

/**
 * @author YueYang
 * Created on 2025/10/20 17:56
 * @version 1.0
 */
@Component
public class GenerateCareTask {

    @Autowired
    private CareTaskMapper careTaskMapper;

    @Autowired
    private CareLevelMapper careLevelMapper;

    private static final Logger log = LoggerFactory.getLogger(GenerateCareTask.class);
    private LocalDate lastWeeklyRunDate;
    private LocalDate lastMonthlyRunDate;

    //构造函数 测试用
    public GenerateCareTask() {
        log.info("=== GenerateCareTask Bean 正在创建 ===");
        try {
            log.info("GenerateCareTask 构造函数执行成功");
        } catch (Exception e) {
            log.error("GenerateCareTask 构造函数异常", e);
        }
    }


    /**
     * 查询所有入住配置信息
     */
    private List<CheckInConfigVO> getAllCheckInConfig() {
        return careTaskMapper.selectCheckInConfigList();
    }


    /**
     * 生成每日护理任务
     */
    private void generateDailyCareTask() {
        // 1. 查询所有入住配置信息
        List<CheckInConfigVO> checkInConfigList = getAllCheckInConfig();

        //2. 创建护理任务集合
        List<CareTask> careTaskList = new ArrayList<>();

        //3.遍历入住配置信息
        for (CheckInConfigVO checkInConfig : checkInConfigList) {
            //4. 获取入住配置中的护理等级id
            Long careLevelId = checkInConfig.getCareLevelId();
            //查询护理等级表 获取对应的护理计划id
            CareLevel careLevel = careLevelMapper.selectCareLevelById(careLevelId.toString());

            // 检查护理等级和护理计划ID是否为空
            if (careLevel == null || careLevel.getCarePlanId() == null || careLevel.getCarePlanId().trim().isEmpty()) {
                System.err.println("护理等级ID " + careLevelId + " 对应的护理计划ID为空，跳过该配置");
                continue;
            }

            //根据护理计划id 查询护理计划中的所有护理项
            List<CarePlanItem> carePlanItemList = careTaskMapper.selectCarePlanItemListByCarePlanId(Integer.parseInt(careLevel.getCarePlanId()));
            //获取当前年月 以便查询老人当前月份账单
            LocalDateTime now = LocalDateTime.now();
            String billMonth = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));
            //查询当前老人的账单
            String billNo = careTaskMapper.selectBillByElderIdAndStartTime(checkInConfig.getElderId(), billMonth);
            //获取当前登录人的用户id
            Long userId = safeGetUserId();

            //5. 遍历护理项 生成这些护理项的每日任务
            for (CarePlanItem carePlanItem : carePlanItemList) {
                //获取该项目的执行频次
                Integer frequency = carePlanItem.getFrequency();
                //获取该项目的执行时间 08:00
                LocalTime executeTime = carePlanItem.getExecuteTime();

                //0 表示每天都执行  1 表示每周执行  2 表示每月执行
                if (carePlanItem.getCycle().equals(0)) {
                    //遍历执行频次
                    //遍历每天任务的执行频次
                    for (int num = 0; num < frequency; num++) {
                        //创建护理任务
                        CareTask careTask = new CareTask();
                        //设置护理任务的各种属性
                        careTask.setProjectId(carePlanItem.getItemId().toString()); //项目id
                        careTask.setElderId(checkInConfig.getElderId().toString()); //老人id
                        careTask.setBedNo(checkInConfig.getBedNo()); //床位号
                        careTask.setTaskType(2); //1.订单任务   2月度任务
                        careTask.setStatus("1"); //1.未执行  2.已执行  3.已取消
                        careTask.setRelatedDocNo(billNo); //关联的账单编号
                        careTask.setCreatedBy(userId.toString()); //创建人
                        careTask.setUpdatedBy(userId.toString()); //更新人
                        careTask.setCreatedAt(new Date()); //创建时间
                        careTask.setUpdatedAt(new Date()); //更新时间

                        //每个频次的执行时间 计算每隔几个小时执行
                        int hour = executeTime.getHour() + 1; // 获取小时部分，例如 9;getHour() 0-23
                        //获取每个几小时执行一次
                        int hourNum = (24 - hour) / frequency; // 例如 9/3 = 3
                        //计算当前频次的执行时间
                        LocalTime executeTimeNum = LocalTime.of(hour + hourNum * num, executeTime.getMinute());
                        //设置执行时间
                        careTask.setExpectedTime(Date.from(executeTimeNum.atDate(now.toLocalDate()).atZone(ZoneId.systemDefault()).toInstant()));


                        //将当前护理任务添加到护理任务集合中
                        careTaskList.add(careTask);
                    }
                }
            }

        }

        //6. 批量插入护理任务（只有当列表不为空时才插入）
        if (!careTaskList.isEmpty()) {
            careTaskMapper.insertBatch(careTaskList);
        }

    }

    /**
     * 生成每周任务
     */
    private void generateWeeklyCareTask() {
        // 1. 查询所有入住配置信息
        List<CheckInConfigVO> checkInConfigList = getAllCheckInConfig();

        //2. 创建护理任务集合
        List<CareTask> careTaskList = new ArrayList<>();

        //3. 遍历入住配置信息
        for (CheckInConfigVO checkInConfigVO : checkInConfigList) {
            //4.根据入住配置信息  生成每周任务
            // 获取入住配置中的护理等级id
            Long careLevelId = checkInConfigVO.getCareLevelId();
            //查询护理等级表 获取对应的护理计划id
            CareLevel careLevel = careLevelMapper.selectCareLevelById(careLevelId.toString());

            // 检查护理等级和护理计划ID是否为空
            if (careLevel == null || careLevel.getCarePlanId() == null || careLevel.getCarePlanId().trim().isEmpty()) {
                System.err.println("护理等级ID " + careLevelId + " 对应的护理计划ID为空，跳过该配置");
                continue;
            }

            //根据护理计划id 查询护理计划中的所有护理项
            List<CarePlanItem> carePlanItemList = careTaskMapper.selectCarePlanItemListByCarePlanId(Integer.parseInt(careLevel.getCarePlanId()));
            //获取当前年月
            LocalDateTime now = LocalDateTime.now();
            String billMonth = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));
            //查询当前老人的账单
            String billNo = careTaskMapper.selectBillByElderIdAndStartTime(checkInConfigVO.getElderId(), billMonth);
            //获取当前登录人的用户id
            Long userId = safeGetUserId();

            //5. 遍历护理项目 生成每周的任务
            for (CarePlanItem carePlanItem : carePlanItemList) {
                //获取该项目的执行频次
                Integer frequency = carePlanItem.getFrequency();
                //获取该项目的执行时间 08:00
                LocalTime executeTime = carePlanItem.getExecuteTime();
                //0 表示每天都执行  1 表示每周执行  2 表示每月执行
                if (carePlanItem.getCycle().equals(1)) {
                    //遍历执行频次
                    //遍历每周任务的执行频次
                    for (int num = 0; num < frequency; num++) {
                        //创建护理任务
                        CareTask careTask = new CareTask();
                        //设置护理任务的各种属性
                        careTask.setProjectId(carePlanItem.getItemId().toString()); //项目id
                        careTask.setElderId(checkInConfigVO.getElderId().toString()); //老人id
                        careTask.setBedNo(checkInConfigVO.getBedNo()); //床位号
                        careTask.setTaskType(2); //1.订单任务   2月度任务
                        careTask.setStatus("1"); //1.未执行  2.已执行  3.已取消
                        careTask.setRelatedDocNo(billNo); //关联的账单编号
                        careTask.setCreatedBy(userId.toString()); //创建人
                        careTask.setUpdatedBy(userId.toString()); //更新人
                        careTask.setCreatedAt(new Date()); //创建时间
                        careTask.setUpdatedAt(new Date()); //更新时间

                        //根据执行频次 计算每周的执行日期
                        //获取今天的日期  例如：2023-10-10
                        LocalDate today = LocalDate.now();
                        //获取执行周期
                        int cycleNum = 7 / frequency; // 例如 7/3 = 2
                        //计算当前频次的执行日期 例如：2025-10-10+2*0 = 2025-10-10
                        LocalDate executeDate = today.plusDays((long) cycleNum * num);
                        //组合日期和时间
                        LocalDateTime executeDateTime = LocalDateTime.of(executeDate, executeTime);
                        //设置执行时间
                        careTask.setExpectedTime(Date.from(executeDateTime.atZone(ZoneId.systemDefault()).toInstant()));

                        //将当前护理任务添加到护理任务集合中
                        careTaskList.add(careTask);
                    }

                }


            }
        }

        //6. 批量插入护理任务（只有当列表不为空时才插入）
        if (!careTaskList.isEmpty()) {
            careTaskMapper.insertBatch(careTaskList);
        }
    }


    /**
     * 生成每月任务
     */
    private void generateMonthlyCareTask() {
        // 1. 查询所有入住配置信息
        List<CheckInConfigVO> checkInConfigList = getAllCheckInConfig();

        //2. 创建护理任务集合
        List<CareTask> careTaskList = new ArrayList<>();

        //3. 遍历入住配置信息
        for (CheckInConfigVO checkInConfigVO : checkInConfigList) {
            //4.根据入住配置信息  生成每月任务
            // 获取入住配置中的护理等级id
            Long careLevelId = checkInConfigVO.getCareLevelId();
            //查询护理等级表 获取对应的护理计划id
            CareLevel careLevel = careLevelMapper.selectCareLevelById(careLevelId.toString());

            // 检查护理等级和护理计划ID是否为空
            if (careLevel == null || careLevel.getCarePlanId() == null || careLevel.getCarePlanId().trim().isEmpty()) {
                System.err.println("护理等级ID " + careLevelId + " 对应的护理计划ID为空，跳过该配置");
                continue;
            }

            //根据护理计划id 查询护理计划中的所有护理项
            List<CarePlanItem> carePlanItemList = careTaskMapper.selectCarePlanItemListByCarePlanId(Integer.parseInt(careLevel.getCarePlanId()));
            //获取当前年月
            LocalDateTime now = LocalDateTime.now();
            String billMonth = now.format(DateTimeFormatter.ofPattern("yyyy-MM"));
            //查询当前老人的账单
            String billNo = careTaskMapper.selectBillByElderIdAndStartTime(checkInConfigVO.getElderId(), billMonth);
            //获取当前登录人的用户id
            Long userId = safeGetUserId();

            //5. 遍历护理项目 生成每月的任务
            for (CarePlanItem carePlanItem : carePlanItemList) {
                //获取该项目的执行频次
                Integer frequency = carePlanItem.getFrequency();
                //获取该项目的执行时间 08:00
                LocalTime executeTime = carePlanItem.getExecuteTime();
                //0 表示每天都执行  1 表示每周执行  2 表示每月执行
                if (carePlanItem.getCycle().equals(2)) {
                    //遍历执行频次
                    //遍历每月任务的执行频次
                    for (int num = 0; num < frequency; num++) {
                        //创建护理任务
                        CareTask careTask = new CareTask();
                        //设置护理任务的各种属性
                        careTask.setProjectId(carePlanItem.getItemId().toString()); //项目id
                        careTask.setElderId(checkInConfigVO.getElderId().toString()); //老人id
                        careTask.setBedNo(checkInConfigVO.getBedNo()); //床位号
                        careTask.setTaskType(2); //1.订单任务   2月度任务
                        careTask.setStatus("1"); //1.未执行  2.已执行  3.已取消
                        careTask.setRelatedDocNo(billNo); //关联的账单编号
                        careTask.setCreatedBy(userId.toString()); //创建人
                        careTask.setUpdatedBy(userId.toString()); //更新人
                        careTask.setCreatedAt(new Date()); //创建时间
                        careTask.setUpdatedAt(new Date()); //更新时间

                        //根据执行频次 计算每月的执行日期
                        //获取今天的日期  例如：2025-10-10
                        LocalDate today = LocalDate.now();
                        //获取执行周期
                        int cycleNum = 30 / frequency; // 例如 30/3 = 10
                        //计算当前频次的执行日期 例如：2025-10-10+10*0 = 2025-10-10
                        LocalDate executeDate = today.plusDays((long) cycleNum * num);
                        //组合日期和时间
                        LocalDateTime executeDateTime = LocalDateTime.of(executeDate, executeTime);
                        //设置执行时间
                        careTask.setExpectedTime(Date.from(executeDateTime.atZone(ZoneId.systemDefault()).toInstant()));

                        //将当前护理任务添加到护理任务集合中
                        careTaskList.add(careTask);
                    }
                }
            }
        }

        //6. 批量插入护理任务（只有当列表不为空时才插入）
        if (!careTaskList.isEmpty()) {
            careTaskMapper.insertBatch(careTaskList);
        }
    }


    /**
     * 应用启动后立即执行一次所有任务
     */
    @PostConstruct
    public void initAllTasks() {
        log.info("=== GenerateCareTask @PostConstruct 方法执行 ===");
        // 执行每日任务
        try {
            generateDailyCareTask();
            log.info("每日护理任务生成完成");
        } catch (Exception e) {
            log.error("每日护理任务生成失败", e);
        }

        // 执行每周任务
        try {
            generateWeeklyCareTask();
            lastWeeklyRunDate = LocalDate.now();
            log.info("每周护理任务生成完成");
        } catch (Exception e) {
            log.error("每周护理任务生成失败", e);
        }

        // 执行每月任务
        try {
            generateMonthlyCareTask();
            lastMonthlyRunDate = LocalDate.now();
            log.info("每月护理任务生成完成");
        } catch (Exception e) {
            log.error("每月护理任务生成失败", e);
        }

        log.info("=== GenerateCareTask 初始化完成 ===");
    }

    @Scheduled(cron = "0 50 23 * * ?")
    public void scheduledDailyTask() {
        log.info("定时任务执行：生成每日护理任务...");
        try {
            generateDailyCareTask();
            log.info("每日护理任务定时生成完成");
        } catch (Exception e) {
            log.error("每日护理任务定时生成失败", e);
        }
    }

    /**
     * 定时任务：每周任务（每天0点触发，判断是否到7天间隔）
     */
    @Scheduled(cron = "0 0 0 * * ?")
    public void scheduledWeeklyTask() {
        LocalDate today = LocalDate.now();
        if (lastWeeklyRunDate == null || ChronoUnit.DAYS.between(lastWeeklyRunDate, today) >= 7) {
            log.info("定时任务执行：生成每周护理任务...");
            try {
                generateWeeklyCareTask();
                lastWeeklyRunDate = today;
                log.info("每周护理任务定时生成完成");
            } catch (Exception e) {
                log.error("每周护理任务定时生成失败", e);
            }
        } else {
            log.info("每周任务未到7天间隔，跳过。上次执行：{}，今天：{}", lastWeeklyRunDate, today);
        }
    }

    /**
     * 定时任务：每隔30天的0点执行每月任务（通过每日0点触发并按间隔判断实现）
     */
    @Scheduled(cron = "0 10 0 * * ?")
    public void scheduledMonthlyTask() {
        LocalDate today = LocalDate.now();
        if (lastMonthlyRunDate == null || ChronoUnit.DAYS.between(lastMonthlyRunDate, today) >= 30) {
            log.info("定时任务执行：生成每月护理任务...");
            try {
                generateMonthlyCareTask();
                lastMonthlyRunDate = today;
                log.info("每月护理任务定时生成完成");
            } catch (Exception e) {
                log.error("每月护理任务定时生成失败", e);
            }
        } else {
            log.info("每月任务未到30天间隔，跳过。上次执行：{}，今天：{}", lastMonthlyRunDate, today);
        }
    }

    private Long safeGetUserId() {
        try {
            return SecurityUtils.getUserId();
        } catch (Exception e) {
            // log.warn("获取用户ID失败，使用系统用户ID: 1", e);
            return 1L;
        }
    }

}


